/*
 *  Copyright (C) 2009  Peter Kist & Jan Ripke
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef __input_ois_keymapper_h
#define __input_ois_keymapper_h 1

#include <functional>
#include <boost/unordered_map.hpp>
#include <boost/serialization/nvp.hpp>

#include <Core/Interface/Input.h>

namespace galaxy {
    namespace input {
        namespace ois_input {

            /** this struct models the key that is mapped to an action */
            class MappedKey {
            public:
                int const m_KeyCode; /**< the scan code for the pressed/released key */
                int const m_Modifiers; /**< the modifier for the key (alt/ctrl or shift) */

                MappedKey(int const keyCode, int const modifiers)
                    : m_KeyCode(keyCode), m_Modifiers(modifiers) { };
            };

            /** this struct is used to serialize the keymap to file */
            class KeyMapDefinition {
                friend class boost::serialization::access;
                template<class Archive>
                void serialize(Archive & ar, const unsigned int version)
                {
                    ar & BOOST_SERIALIZATION_NVP(m_KeyCode)
                        & BOOST_SERIALIZATION_NVP(m_Modifier) 
                        & BOOST_SERIALIZATION_NVP(m_Action);
                }

            public:
                int m_KeyCode;
                int m_Modifier;
                int m_Action;

                KeyMapDefinition() : m_KeyCode(0), m_Modifier(0), m_Action(0) { };
                KeyMapDefinition (int keycode, int modifier, int action)
                    : m_KeyCode(keycode), m_Modifier(modifier), m_Action(action)
                {
                }
            };

            /** The KeyMapper is responsible for mapping key scan codes (with modifiers) to input actions
            */
            class KeyMapper {

                struct iequal_to
                    : std::binary_function<MappedKey, std::string, bool>
                {
                    bool operator()(MappedKey const& x,
                        MappedKey const& y) const
                    {
                        if (x.m_KeyCode == y.m_KeyCode && x.m_Modifiers == y.m_Modifiers) {
                            return true;
                        }
                        return false;
                    }
                };

                struct ihash
                    : std::unary_function<MappedKey, std::size_t>
                {
                    std::size_t operator()(MappedKey const& x) const
                    {
                        std::size_t seed = 0;
                        boost::hash_combine(seed, x.m_KeyCode);
                        boost::hash_combine(seed, x.m_Modifiers);
                        return seed;
                    }
                };


                typedef boost::unordered_map<MappedKey, KeyAction, ihash, iequal_to> KeyMap;

                KeyMap    m_KeyMap;
                KeyAction m_DefaultAction;

            public:
                KeyMapper ();
                virtual ~KeyMapper ();

                /** Loads a keymap into the keymapper. 
                * The mapname is used as filename for the keymap file.
                * @param mapName The (file) name for the key map.
                * @return true upon success, false upon failure.
                */
                bool loadKeyMap (std::string& mapName);
                /** Loads a keymap into the keymapper. 
                * The mapname is used as filename for the keymap file.
                * @param mapName the (file) name for the key map.
                * @return true upon success, false upon failure.
                */
                bool saveKeyMap (std::string& mapName);

                /** Links the specified key to the specified action 
                * @param mappedKey The key to map.
                * @param keyAction The action to which the key must be mapped.
                * @return Always returns true.
                */
                virtual bool linkMappedKeyToAction (MappedKey mappedKey, KeyAction keyAction);
                /** Set the default action. The default action is returned when a getAction 
                * is performed for a key that is not present in the mapper.
                * @param defaultAction The default action for the current mapper.
                */
                virtual void setDefaultAction (KeyAction defaultAction) { m_DefaultAction = defaultAction; };

                virtual KeyAction getAction (MappedKey& mappedKey);
                /** get action taking the modifier into account */
                virtual KeyAction getAction (int keyCode, int modifiers);

            private:
                std::string getKeyMapPath (std::string& mapName);
            };

        }
    } // namespace input
} // namespace galaxy

#endif // __input_ois_keymapper_h //
